﻿/*
 * Copyright the original author or authors.
 * 
 * Licensed under the MOZILLA PUBLIC LICENSE, Version 1.1 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.mozilla.org/MPL/MPL-1.1.html
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import com.bourre.log.PixlibStringifier;
import com.bourre.transitions.AbstractTween;
import com.bourre.transitions.IFrameListener;

import com.kairos.engine.RTBeacon;
import com.kairos.engine.RTEvent;
import com.kairos.log.KairosDebug;

/**
 * @author Francis Bourre, Kairos adaptation by Cédric Néhémie
 */

class com.kairos.transitions.BasicTweenRT extends AbstractTween implements IFrameListener
{
	//-------------------------------------------------------------------------
	// Private properties
	//-------------------------------------------------------------------------
	
	private var _nCurrentTime:Number;

	private var _nLocalSpeed : Number;
	
	//-------------------------------------------------------------------------
	// Public API
	//-------------------------------------------------------------------------
	
	/**
	 * Constructs a new {@code BasicTweenRT} instance.
	 * 
	 * @param oT 	Object which the Tween targets.
	 * @param sP 	Setter (method or property).
	 * @param nE 	Ending value of property.
	 * @param nRate Length of time of the motion in milliseconds.
	 * @param nS 	(optional) Starting value of property.
	 * @param fE 	(optional) Easing function .
	*/
	public function BasicTweenRT(oT, sP, nE:Number, nRate:Number, nS:Number, fE:Function)
	{
		super( oT, sP, nE, nRate, nS, fE );
		_oBeacon = RTBeacon.getInstance();
		_nLocalSpeed = 1;
	}
	
	/**
	 * Returns the string representation of this instance.
	 * @return the string representation of this instance
	 */
	public function toString() : String 
	{
		return PixlibStringifier.stringify( this );
	}
	
	/**
	 * Start tweening.
	 * 
	 * <p>{@link AbstractTween#execute} overridding.
	 * 
	 * <p>{@link com.bourre.commands.Command} polymorphism.
	 */
	public function execute() : Void
	{
		_nCurrentTime = 0;
		super.execute();		
	}
	
	/**
	 * {@link AbstractTween#onEnterFrame} overridding to add real time
	 * behavior.
	 */
	public function onEnterFrame() : Void
	{
		if (_isMotionFinished( RTEvent( arguments[ 0 ] ).getStep() * _nLocalSpeed ) )
		{
			_onMotionEnd();
		} else
		{
			_onUpdate();
		}
	}
	
	//-------------------------------------------------------------------------
	// Private implementation
	//-------------------------------------------------------------------------
	
	private function _isMotionFinished( d : Number ) : Boolean
	{
		_nCurrentTime += Math.abs( d );
		return _nCurrentTime >= _nRate;
	}
	
	private function _onUpdate() : Void
	{
		
		_oSetter.setValue( _fE(_nCurrentTime, _nS, _nE - _nS, _nRate) );
	}

	/**
	 * Defines a new {@code FrameBeacon} object the object will run on.
	 * 
	 * <p>Use that method carefully, if you have objects in your scene witch 
	 * are plugged on two beacon witch have differents settings you can loose
	 * synchronisation between those objects.</p>
	 * 
	 * <p>If the passed-in beacon is null, the function failed and throw an error
	 * on the Kairos log channel.</p>
	 * 
	 * @param  beacon {@code FrameBeacon} to register with.
	 * @throws Error The passed-in beacon is null.
	 */
	public function setFrameBeacon( beacon : RTBeacon ) : Void 
	{
		if( !beacon )
		{
			KairosDebug.ERROR( "Attempting to define a null beacon in " + this );
			throw new Error ( "Attempting to define a null beacon in " + this );
		}
		
		if( !_bP )
		{
			_oBeacon = beacon;
		}
		else
		{
			stop();
			_oBeacon = beacon;
			start();
		}
	}

	/**
	 * Returns the {@code RTBeacon} used by the current object.
	 * 
	 * @return {@code RTBeacon} used by the current object.
	 */
	public function getFrameBeacon() : RTBeacon 
	{
		return RTBeacon( _oBeacon );
	}
	
	/**
	 * Defines the local speed factor for the current object. Local speed works
	 * as a multiplier for the time step value received from the beacon - as the
	 * {@code setGlobalSpeed} feature of the RTBeacon.
	 * 
	 * <p>The default {@code setLocalSpeed} method don't support value lower
	 * or equals than 0, override it if you want to avoid negative values.</p>
	 * 
	 * @param 	rate float number used as multiplier for the current time step
	 * @throws 	Error The value specified in {@code setLocalSpeed}
	 * 			isn't supported by the current object.	
	 */
	public function setLocalSpeed(rate : Number) : Void 
	{
		if( rate <= 0 )
		{
			KairosDebug.ERROR( this + " don't support local speed lower or equals than 0 : " + rate );
			throw new Error ( this + " don't support local speed lower or equals than 0 : " + rate );
		}
		
		_nLocalSpeed = rate;
	}
	/**
	 * Returns the current local speed factor of the object.
	 * 
	 * @return {@code Number} local speed of the object.
	 */
	public function getLocalSpeed() : Number
	{
		return _nLocalSpeed;
	}
}